Imports System.Drawing
Imports Microsoft.Win32
Imports System.Windows.Forms

''' <summary>
''' Create an instance of this class in the constructor of a form in .NET 2.0
''' Will save and restore window state, size, and position.
''' Uses DesktopBounds (instead of just Form.Location/Size) 
''' to place window correctly on a multi screen desktop.
''' </summary>
Public Class FormState

    Private _parent As Form
    Private _registry_key As String

    ''' <summary>
    ''' Initializes an instance of the FormState class.
    ''' </summary>
    ''' <param name="parent">
    ''' The form to store settings for.
    ''' </param>
    ''' <param name="sub_key">
    ''' Registry path from HKEY_CURRENT_USER to place for storing settings.
    ''' Will create a subkey named "FormState".
    ''' </param>
    Public Sub New(ByVal parent As Form, ByVal subkey As String)
        Me._parent = parent
        Me._registry_key = "Software\Gaia\" & subkey & "\FormState"
        AddHandler Me._parent.Load, New EventHandler(AddressOf On_Load)
        AddHandler Me._parent.FormClosed, New FormClosedEventHandler(AddressOf On_FormClosed)
    End Sub

    Public Sub SaveValue(ByVal name As String, ByVal value As Object)
        Me.RegKey.SetValue(name, value)
    End Sub

    Public Function GetValue(ByVal name As String, ByVal default_value As Object) As Object
        Return Me.RegKey.GetValue(name, default_value)
    End Function

    ''' <summary>
    ''' If for some reason the value stored in reg cannot be parsed to int 
    ''' the default_value is returned.
    ''' </summary>
    Public Function GetIntValue(ByVal name As String, ByVal default_value As Integer) As Integer
        Dim val As Integer = default_value
        If Not Integer.TryParse(Me.RegKey.GetValue(name, default_value).ToString(), val) Then
            val = default_value
        End If
        Return val
    End Function

    Private ReadOnly Property RegKey() As RegistryKey
        Get
            Return Registry.CurrentUser.CreateSubKey(Me._registry_key & "\" & Me._parent.Name)
        End Get
    End Property

    Private Sub On_Load(ByVal sender As Object, ByVal e As EventArgs)
        Dim X As Integer, Y As Integer, width As Integer, height As Integer, window_state As Integer

        ' place to get settings from
        Dim key As RegistryKey = Me.RegKey

        If Not Integer.TryParse(key.GetValue("DesktopBounds.Width", Me._parent.DesktopBounds.Width).ToString(), width) Then
            width = Me._parent.DesktopBounds.Width
        End If
        If Not Integer.TryParse(key.GetValue("DesktopBounds.Height", Me._parent.DesktopBounds.Height).ToString(), height) Then
            height = Me._parent.DesktopBounds.Height
        End If
        If Not Integer.TryParse(key.GetValue("DesktopBounds.X", Me._parent.DesktopBounds.X).ToString(), X) Then
            X = Me._parent.DesktopBounds.X
        End If
        If Not Integer.TryParse(key.GetValue("DesktopBounds.Y", Me._parent.DesktopBounds.Y).ToString(), Y) Then
            Y = Me._parent.DesktopBounds.Y
        End If

        ' In case of multi screen desktops, check if we got the
        ' screen the form was when closed.
        ' If not there we put it in upper left corner of nearest 
        ' screen.
        ' We don't bother checking size (as long as the user see
        ' the form ...).
        Dim screen_bounds As Rectangle = Screen.GetBounds(New Point(X, Y))
        If X > screen_bounds.X + screen_bounds.Width Then
            X = screen_bounds.X
            Y = screen_bounds.Y
        End If

        Me._parent.DesktopBounds = New Rectangle(X, Y, width, height)

        If Not Integer.TryParse(key.GetValue("WindowState", CInt(Me._parent.WindowState)).ToString(), window_state) Then
            window_state = CInt(Me._parent.WindowState)
        End If

        Me._parent.WindowState = CType(window_state, FormWindowState)
    End Sub

    Private Sub On_FormClosed(ByVal sender As Object, ByVal e As FormClosedEventArgs)
        ' There may be cases where the event is raised twice.
        ' To avoid handling it twice we remove the handler.
        RemoveHandler Me._parent.FormClosed, New FormClosedEventHandler(AddressOf On_FormClosed)
        ' TODO: find out why it is raised twice ...

        ' place to store settings
        Dim key As RegistryKey = Me.RegKey

        ' save window state
        key.SetValue("WindowState", CInt(Me._parent.WindowState))

        ' save pos & size in normal window state
        If Me._parent.WindowState <> FormWindowState.Normal Then
            Me._parent.WindowState = FormWindowState.Normal
        End If
        key.SetValue("DesktopBounds.Y", Me._parent.DesktopBounds.Y)
        key.SetValue("DesktopBounds.X", Me._parent.DesktopBounds.X)
        key.SetValue("DesktopBounds.Width", Me._parent.DesktopBounds.Width)
        key.SetValue("DesktopBounds.Height", Me._parent.DesktopBounds.Height)
    End Sub

End Class
